﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cofe.Core.Interfaces;

namespace Cofe.Core.Property
{
    public class MemoryPropertyCache : IPropertyCache
    {


        #region Constructor

        [Export(typeof(ICofeService))]
        [ServicePriority(ServicePriorityAttribute.DefaultPriority_COFE)]
        public class Factory : IPropertyCacheFactory
        {
            static Dictionary<string, MemoryPropertyCache> _memoryCacheDic =
                new Dictionary<string, MemoryPropertyCache>();

            public virtual IPropertyCache CreatePropertyCache(ParsableType pathType, string path)
            {
                if (pathType != ParsableType.ParsePath)
                    throw new NotSupportedException();

                var newCache = new MemoryPropertyCache();
                newCache.SetPropertyAsync(CofeProperties.FullParseName, path).Wait();
                return newCache;
            }

            public virtual IPropertyCache CreatePropertyCache()
            {
                return new MemoryPropertyCache();
            }

            public virtual IPropertyCache CreatePropertyCache(IPropertyCache[] propertyCaches)
            {
                var pcs = propertyCaches.Select(pc => (pc as MemoryPropertyCache)._propertyCacheDictionary).ToArray();
                var pcd = IPropertyCacheDictionaryExtension.Combine(pcs);
                        
                return new MemoryPropertyCache()
                {
                    _propertyCacheDictionary = pcd
                };
            }

            public virtual ParsableType SupportedParsableType
            {
                get { return ParsableType.ParsePath; }
            }
        }

        public MemoryPropertyCache()
        {
            _propertyCacheDictionary = new PropertyCacheDictionary();
        }

        #endregion

        #region Methods

        #region CanCache / IsPropertySupported / ReadOnly
        public bool CanCache(object property)
        {
            if (!(CofeServices.PropertyDictionary.AttributeHelper.IsCachable(property)))
                return false;

            return !(DecoratorExtension.IsAction(property));
        }


        public virtual bool IsPropertySupported(object property)
        {
            switch ((int)property)
            {
                case (int)CofeProperties.RefreshAsync:
                    return true;
            }

            return _propertyCacheDictionary.GetPropertiesInDic().Contains(property);
        }


        public bool IsPropertyReadOnly(object property)
        {
            return false;
        }
        #endregion

        #region ResetChanges / Cache

        public void ResetChanges()
        {
            _propertyCacheDictionary.ClearDictionary(true, false, null);
        }

        public void ResetCache(Func<object, bool> filter)
        {
            _propertyCacheDictionary.ClearDictionary(true, true, filter);
        }


        public Task RefreshAsync()
        {
            _propertyCacheDictionary.ClearDictionary(true, true, null);
            return Task.Delay(0);
        }

        #endregion


        #region getProperty / GetPropertyAsync

        protected virtual PropertyPair getProperty(object property)
        {
            switch ((int)property)
            {
                case (int)CofeProperties.RefreshAsync:
                    Func<ParameterDic, Task> func = (pm) => RefreshAsync();
                    return PropertyPair.FromValue(property, func);
            }

            if (_propertyCacheDictionary.GetPropertiesInDic().Contains(property))
                return _propertyCacheDictionary.GetProperty(property);

            return null;
        }

        public Task<PropertyPair[]> GetPropertyAsync(object property)
        {
            PropertyPair val = getProperty(property);
            PropertyPair[] retVal = val == null ? null : new PropertyPair[] { val };
            return Task<PropertyPair[]>.FromResult(retVal);
        }


        #endregion

        #region CachePropertyAsync / SetPropertyAsync

        public Task<bool> CachePropertyAsync(params PropertyPair[] ppairs)
        {
            foreach (var pp in ppairs)
                _propertyCacheDictionary.CacheProperty(pp);
            return Task<bool>.FromResult(false);
        }


        public Task<bool> SetPropertyAsync(PropertyPair propertyPair)
        {
            _propertyCacheDictionary.SetProperty(propertyPair);

            var returnHandled = Cofe.Core.PropertyDefinitions.CacheDefinitions
                .GetSupportedProperties().Contains(propertyPair.Property);
            return Task<bool>.FromResult(returnHandled);
        }

        public override string ToString()
        {
            return String.Format("MPC2: Cached:{0}, Changed{1}", CachedProperties.Count(), ChangedProperties.Count());
        }

        
        #endregion


        #region DataStore - not implemented

        public virtual Task WriteToDataStore()
        {
            throw new NotImplementedException();
        }

        public virtual Task ReadFromDataStore()
        {
            throw new NotImplementedException();
        }

        #endregion
       

        #endregion

        #region Data

        private IPropertyCacheDictionary _propertyCacheDictionary;
        private IPropertyDictionary _propertyDictionary = null;

        #endregion

        #region Public Properties

        public IPropertyCacheDictionary PropertyCacheDictionary { get { return _propertyCacheDictionary; } }

        public IPropertyDictionary PropertyDictionary
        {
            get
            {
                return _propertyDictionary ??
                    (_propertyDictionary = CofeServices.PropertyDictionary);
            }
            set { _propertyDictionary = value; }
        }

        public List<object> CachedProperties { get { return _propertyCacheDictionary.GetCachedProperties().ToList(); } }
        public List<object> ChangedProperties { get { return _propertyCacheDictionary.GetChangedProperties().ToList(); } }
        public virtual IPropertyDefinitions[] SupportedDefinitions { get { return _propertyCacheDictionary
            .GetSupportedDefinitions(); } }

        #endregion












    }
}
